package com.zzyl.service.impl;

import cn.hutool.core.bean.BeanUtil;
import cn.hutool.core.util.ObjectUtil;
import cn.hutool.crypto.digest.BCrypt;
import cn.hutool.json.JSONUtil;
import com.zzyl.constant.CacheConstant;
import com.zzyl.constant.SuperConstant;
import com.zzyl.dto.LoginDto;
import com.zzyl.entity.User;
import com.zzyl.enums.BasicEnum;
import com.zzyl.exception.BaseException;
import com.zzyl.mapper.ResourceMapper;
import com.zzyl.mapper.UserMapper;
import com.zzyl.properties.JwtTokenManagerProperties;
import com.zzyl.properties.SecurityConfigProperties;
import com.zzyl.service.UserService;
import com.zzyl.utils.JwtUtil;
import com.zzyl.vo.UserVo;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.data.redis.core.StringRedisTemplate;
import org.springframework.stereotype.Service;

import java.util.HashMap;
import java.util.List;
import java.util.Map;
import java.util.concurrent.TimeUnit;

@Service
public class UserServiceImpl implements UserService {

    @Autowired
    private UserMapper userMapper;

    @Autowired
    private JwtTokenManagerProperties jwtTokenManagerProperties;

    @Autowired
    private ResourceMapper resourceMapper;

    @Autowired
    private SecurityConfigProperties securityConfigProperties;

    /*@Autowired
    private RedisTemplate<String,String> redisTemplate;*/

    @Autowired
    private StringRedisTemplate stringRedisTemplate;

    /**
     * 登录接口
     *
     * @param loginDto
     * @return
     */
    @Override
    public UserVo login(LoginDto loginDto) {
        //1. 校验参数是否合法
        if(ObjectUtil.isEmpty(loginDto)
                || ObjectUtil.isEmpty(loginDto.getUsername())
                || ObjectUtil.isEmpty(loginDto.getPassword())){
            throw new BaseException(BasicEnum.PARAM_ERROR);
        }

        //2. 根据用户名查询用户信息 如果为空 则抛出异常 提示用户登录失败
        User user = userMapper.selectByName(loginDto.getUsername());
        if(ObjectUtil.isEmpty(user)){
            throw new BaseException(BasicEnum.LOGIN_FAIL);
        }

        //3. 判断用户的状态是否为禁用 如果是 则抛出异常 提示账号已禁用
        if(user.getDataState().equals(SuperConstant.DATA_STATE_1)){
            throw new BaseException(BasicEnum.ACCOUNT_DISABLED);
        }

        //4. 判断密码是否相等 如果不等 则抛出异常 提示用户名或者密码错误 易错点：校验的时候 第一个参数是明文 第二个参数是密文
        if(!BCrypt.checkpw(loginDto.getPassword(), user.getPassword())){
            throw new BaseException(BasicEnum.INCORRECT_PASSWORD);
        }

        //5. 对查询到的用户数据进行脱敏处理
        user.setPassword("");

        //6. 生成token
        UserVo userVo = BeanUtil.toBean(user, UserVo.class);
        Map<String, Object> param = new HashMap<>();
        param.put("currentUser", JSONUtil.toJsonStr(userVo));
        String token = JwtUtil.createJWT(jwtTokenManagerProperties.getBase64EncodedSecretKey(),
                jwtTokenManagerProperties.getTtl(),
                param);

        //7. 封装并返回结果
        userVo.setUserToken(token);

        //8. 根据用户的id查询用户的按钮资源
        List<String> urlList = resourceMapper.selectByUserId(user.getId());

        //9. 获取白名单的数据
        List<String> publicAccessUrls = securityConfigProperties.getPublicAccessUrls();

        //最终的权限列表
        urlList.addAll(publicAccessUrls);

        //10. 把权限列表存储到redis
        stringRedisTemplate.opsForValue().set(CacheConstant.PUBLIC_ACCESS_URLS+user.getId(),
                JSONUtil.toJsonStr(urlList), jwtTokenManagerProperties.getTtl()/1000, TimeUnit.SECONDS);

        return userVo;
    }
}
